package com.baomibing.flow.enginee;

import com.alibaba.fastjson.annotation.JSONField;
import com.baomibing.core.exception.ServerRuntimeException;
import com.baomibing.flow.constant.JoinExeTypeEnum;
import com.baomibing.flow.constant.ProcessTypeEnum;
import com.baomibing.flow.exception.FlowExceptionEnum;
import com.baomibing.flow.execute.Execution;
import com.baomibing.flow.model.JoinNode;
import com.baomibing.flow.model.WorkFlow;
import com.baomibing.flow.model.WorkNode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.List;

/**
 * JoinProcess
 *
 * @author frog 2023/9/22 10:53
 * @version 1.0.0
 **/

@Getter @ToString
public class JoinProcess extends Process {

    @JSONField(deserialize=false)
    @Setter
    private List<SubProcess> processes;

    @JSONField(deserialize=false)
    @Setter
    private SubProcess targetProcess;


    public JoinProcess(WorkFlow flow) {
        super(flow);
        this.processType = ProcessTypeEnum.JOIN.name();
    }

    @Override
    public boolean beComplete() {
        for (SubProcess p : processes) {
            if (!p.beComplete()) {
                return false;
            }
        }
        return true;
    }

    private void doInternalProcess(Execution execution) {
        targetProcess.doProcess(execution);
    }


    public boolean matchSource(WorkNode source) {
        return processes.stream().anyMatch(p -> p.getTarget().getName().equals(source.getName()));
    }


    @Override
    public boolean doProcess(Execution execution) {
        JoinNode joinNode = (JoinNode)targetProcess.getSource();
        for (SubProcess p : processes) {
            //执行类型是全部达到后，在执行
            if (!p.beComplete() && JoinExeTypeEnum.ALL.equals(joinNode.getExeType())) {
                return false;
            }
            //执行类型是任一达到后，在执行
            if (p.beComplete() && JoinExeTypeEnum.ANY.equals(joinNode.getExeType())) {
                break;
            }
        }
        doInternalProcess(execution);
        return true;
    }

    @Override
    public boolean doReject(Execution execution) {
        if (targetProcess.beComplete()) {
            throw new ServerRuntimeException(FlowExceptionEnum.TARGET_PROCESS_OF_JOIN_PROCESS_HAVE_BEEN_COMPLETE);
        }
        for (SubProcess p : processes) {
            if (!p.beComplete()) {
                continue;
            }
            if (!p.doReject(execution)) {
                return false;
            }
        }
        return true;
    }

    public void doVirtualReject() {
        targetProcess.doVirtualReject();
        for (SubProcess p : processes) {
            p.doVirtualReject();
        }
    }


}
